'''Copyright 2009 Marcus Wanner, Colin Rooney

This file is part of the Python Debug Logging Suite.

The Python Debug Logging Suite is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

The Python Debug Logging Suite is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with The Python Debug Logging Suite.  If not, see
<http://www.gnu.org/licenses/>.

Note that you need to run logserver.py while you use this module, or
you will not see any logging output.'''

import socket, time, sys
time.clocktime() #needed so that the timestamp is in consistent units, don't ask why

class liveobj():
    'Object to handle the logserver connection.'
    
    def __init__(self):
        'Initializes the liveobj. Any number of connections can be open at a time.'
        self._valid = 1 #object is valid at start, obviously.
        self.timestamp = 0 #timestamp is turned off by default. Should this be changed?
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def _checkvalid(self):
        # This is at a higher level of apstraction in case we want to change it
        if self._valid == 0:
            raise NameError, 'Object is no longer valid.' #we need to find a better error type

    def ping(self):
        'Use to ping the server to test if it exists and can send and revieve messages. Timeout is 10 seconds.'
        self._checkvalid()
        
        #note that this function assumes that the server will not send any messages to port 38477 that don't relate to pinging.
        
        self._pingstart = time.time() #Get the start time
        self._pingsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #Make a new pingsocket
        self._pingsock.bind(('localhost', 38477)) #bind it to a port
        self._pingsock.settimeout(10)

        self.msg('_PING_SERVER') #Send the ping magic word

        try:
            inmsg, addr = self._pingsock.recvfrom(1024) #Get a reply.
        except socket.timeout:
            self._pingsock.close() #close the pingsock
            self.msg('Ping Failed.') #Send a failed message to the server, in case it's listening
            return 'Ping Failed. Socket timeout.'
        except:
            self._pingsock.close() #close the pingsock
            self.msg('Ping Failed.') #Send a failed message to the server, in case it's listening
            return 'Ping Failed. Unhandled error: '+str(sys.exc_info()[1])
        
        self._pingsock.close() #close the pingsock

        self.latestpingtime = time.time()-self._pingstart #write the ping time to an object variable
        self.msg('Ping Succeded. Time: ' + str(self.latestpingtime)) #Tell the server that the ping succeded
        return self.latestpingtime
    
    def msg(self, msgtext):
        'Use to send a message to the logserver display. Input can be any type.'
        self._checkvalid()
        if self.timestamp == 1: #get the timestamp setting
            msgtext = str(time.clocktime()) + ': ' + str(msgtext) #timestamp 

        self._sock.sendto(str(msgtext), ('localhost', 61307)) #actually send it

    def close(self):
        'Destroys the object (sort of).'
        self._checkvalid()
        self._sock.close() #closes the socket. This doesn't actually do anything as it's not a stream socket.
        self._valid = 0 #invalidate the object

    def __del__(self):
        self._sock.close()
